iT邦幫忙

2024 iThome 鐵人賽

DAY 10
1
自我挑戰組

學習網頁開發系列 第 10

CSRF, CORS

  • 分享至 

  • xImage
  •  

架構

  1. same origin policy
  2. cross-origin resource sharing
  3. cross-site request forgery

內文

CORS(Cross-Origin Resoure Sharing)和 CSRF(Cross-Site Request Forgery) 都是與網路通訊相關的知識,兩者也時常被搞混成同一個東西,但卻是完全不同的東西。 跨站請求偽造(CSRF)是一種惡意攻擊手段,而跨網域資源共享(CORS)則是一種瀏覽器的安全政策、規範。

1. Same origin policy

首先定義何謂同網域。只要Scheme(protocol)、Domain、Port一樣的URL(unifrom resource locater)即為同網域。
https://www.example.com:80/will-chen為例:

https www.example.com 80 will-chen
scheme (protocol) Domain Port path

我們即可如此判斷以下是否為同源:

網址 使否同源 原因
http://www.example.com/ 不同源 protocol 不同
https://example.com/ 不同源 domain 不同
http://www.example.com:1000/ 不同源 port 不同
http://www.example.com/aloha 同源

瀏覽器http預設的連接埠(port)多為80。不同protocol有不同的預設,例如FTP就是預設21, SMTP是587

HTML 跨來源write, read

same origin policy 允許不同來源的寫入。例如scriptlinkimgiframe等都可以從其他地方直接匯入需要的資料。
但same origin policy會擋掉跟js 相關的資料請求。例如fetchXMLHttpRequest等就會被阻止。另外也無法獲取其他網域的cookie。

2. 跨網域資源共享

什麼是CORS

雖然same origin policy基於安全性,有其存在價值,但有時候我們必需要繞過它。最常見的案例就是API。不同網域間的資料轉換至關重要,因此也就發展出了CORS的概念。基本概念就是:由伺服器指定哪些不同源的的請求是可以被接受的,哪些不行。

要實作的方法並不複雜,基本就是把相關資格藏在request的header中,至於格式或是方法的選擇基本由後端決定,前端照著走就是了。

而除了部分simple request,其餘的請求在正式發出請求前,還有一個preflight request(METHOD 名為:OPTION)先詢問伺服端這個網域是否符合其CORS資格。符合的話,才會再發出真正的請求。此二階段方法可以避免傳遞不必要的資料,節省頻寬。

Sending with credentials

不論是早期的XMLHttpRequest,原生的fetch,或是axios的get或其他請求方法都不會自動加入認證。因此都需要手動在發出請求時標明withCredential: true之類的字樣。這與HTML的請求會直接嵌入同網域的cookie是不一樣的。
不過要注意,這些請求能否加上特定cookie資訊還要看cookie的SameSite設定。(此文下面剛好有介紹到SameSite的不同狀態。)

3. 跨站偽造請求

什麼是跨站偽造請求

簡單來說,利用伺服器對特定瀏覽器的信任進行惡意操作。具體而言,當一個使用者登入某網站後,網站或將對使用者的認證存儲於瀏覽器內,以方便使用者後續發送請求時能夠確認身份。這時,假如認證尚未被清除,只要第三方能夠得到這個認證,便有機會冒用某使用者的身份,騙過伺服器以執行目標操作。

流程大致如下:

  1. 使用者登入特定網站,網站將認證存於瀏覽器
  2. 使用者點到惡意網址
  3. 惡意網址套用瀏覽器內認證,向網站伺服器端發送請求,達成目標

舉例來說,使用者登入其銀行帳戶後,惡意方誘使用者點擊某網址,盜取其網路銀行的身份認證,並偷偷轉移帳戶內資金。這就是一個簡易的跨站偽造請求。任何可以產生跨域請求的 html tag 都是 CSRF 攻擊發生的媒介,例如form tag或是a tag甚。至有心的話,特定套件能讓所有html tag都產生跨域請求,成為幫兇。

當然現代網站大都不會如此毫不設防。就以舉例中的銀行為例,簡訊認證或是更多的認證都是基本的保護措施。但一個較小型的網站仍要小心此攻擊手段。

如何防範跨站偽造請求

  1. 不允許GET request做任何改變資料的請求
    這是最簡單的手段,在伺服端就應該做好相關設定。
    不然某些惡意網站能夠加入隱形的image,然後其src直接包含一個GET request. 這樣只要使用者瀏覽這惡意網站,就會觸發CSRF。
  2. 加上驗證
    如同上述舉的例子,最簡單的驗證方式就是雙重驗證。可以加上圖形驗證碼、簡訊驗證等不同手法,讓使用者確定自己要執行此操作,並再次確認其身份。
  3. 檢查header 中的 Referer
    由於header 會包含referer這個轉遞的網域,可以檢查看是否包含不知名的第三方。然而此操作也有風險,因為JS想改的話也可以改掉這個。
  4. The Synchronizer Token pattern (CSRF token的一種)
    此token由伺服器端生成,會在每一個請求生成,儲存一份在伺服端。接著,這個token會傳回客戶端,可以隱藏起來。當客戶這次請求提交過來時,可以包成整體的一部分,或是作為header的部分,一起提交過來。接著伺服器再對照是否符合請求紀錄或是session。

django 如何實作csrf token

  1. Double Submit Cookies (CSRF token的一種)
    一登入後,伺服端生成一個csrf token,並直街回傳給使用者,不儲存在伺服器。提交每一個請求時,header和body同時都會包含csrf token。這時伺服端只要比對兩邊的token是否一致即可。
    而攻擊者因為CORS規範,無法直接讀取使用者瀏覽器cookie內的token,也因此無法複製一份相印的token到form 中。
    相較於the synchronoizer token pattern,double submit cookies可以減少伺服器儲存token的需求。

django其實也內建double submit cookies機制

  1. SameSite
    這是HTML5後,瀏覽器提供的一個property,主要針對cookies的保護。由於cookies預設會加在header跟request送出去,samesite 這個property就可以另外設定cookie應該在哪種情況下被送出。它總共有三個value:LaxStrictNone
    a. Strict:最為嚴格,只有在當下網域和URL網域相同時會附上。例如在一個臉書頁面點到github的連結時,由於不為同網域,將不帶設定好的cookie內容過去。因此雖然可能你當下已在另一個tab登入github,github一就會要求你再次登入。
    這麼做使用者體驗當然不會太好,因此主要用在處理金流等極度敏感事項。
    b. Lax:最常見的設定。除了GET外,其他第三方請求也不會發送cookies.
    c. None:最鬆散,允許所有請求都放上cookie。
請求類型 code Strict Lax None
超連結 <a href="....."></a> 不允許 允許 允許
連結/CSS,favicon <link rel=".." href=".." /> 不允許 允許 允許
GET form <form method="GET"></form> 不允許 允許 允許
POST form <form method="POST"></form> 不允許 不允許 允許
iframe <iframe src=".."></iframe> 不允許 不允許 允許
AJAX(任何JS相關都是) hx-post="..." 不允許 不允許 允許
image <img src="..."> 不允許 不允許 允許

直得注意的是,就算samesite 設定為 Strict,仍有機會被XSS嵌入惡意腳本,導致cookie流出。至此,csrf就會成功。因此,一般會建議另外再加上HttpOnly的設定來防範XSS。

延伸相關知識

  1. authentication => session id or the session info in the cookie
  2. session cookie vs persistent cookie
  3. cookie vs localstorage vs sessionstorage
  4. cross-site scripting (XSS)
  5. Http cookies attributes: Secure, HttpOnly, SameSite

reference

  1. https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
  2. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
  3. https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSRF_prevention
  4. https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
  5. https://stackoverflow.com/questions/20504846/why-is-it-common-to-put-csrf-prevention-tokens-in-cookies

上一篇
Django 分頁
下一篇
Nginx
系列文
學習網頁開發13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言